package com.vaye.im.websocket;

import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.vaye.common.constant.CacheConstant;
import com.vaye.common.utils.RedisUtil;
import com.vaye.common.utils.SpringContextUtils;
import com.vaye.im.dto.TopicMsg;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 聊天(群聊版)
 * 该类已经废弃，如果使用请移步优化后的版本：{@link ProductWebSocket31}
 * @author wangzhiyong
 * @date 2022年04月04日 上午8:24
 * 1） value = "/ws/{userId}"
 * onOpen(@PathParam("userId") String userId, Session session){ // ... }
 * 这种方式必须在前端在/后面拼接参数 ws://localhost:7889/productWebSocket/123 ，否则404
 *
 * 2） value = "/ws"
 * onOpen(Session session){ // ... }
 * Map<String, List<String>> requestParameterMap = session.getRequestParameterMap();
 * // 获得 ?userId=123 这样的参数
 * @author bart
 */
@Slf4j
@Component
@ServerEndpoint(value = "/chat1/{roomId}/{userId}") //添加消息编码器
@Deprecated
public class ProductWebSocket3 {

    // 当前登录用户的id和websocket session的map
    private static ConcurrentHashMap<String, List<Pair<String,Session>>> roomIdSessionMap = new ConcurrentHashMap<>();

    //房间在线人数统计
    private static ConcurrentHashMap<String, AtomicInteger> rootNumMap = new ConcurrentHashMap();

    @OnOpen
    public void onOpen(@PathParam("roomId") String roomId, @PathParam("userId") String userId, Session session){
        if (StringUtils.isEmpty(roomId) || StringUtils.isEmpty(userId)) {
            log.error("websocket连接 缺少参数");
            throw new IllegalArgumentException("websocket连接 缺少参数");
        }
        log.info("websocket 新客户端连入，用户id：{},房间id={}",userId,roomId);
        Pair<String,Session> pair = Pair.of(userId,session);
        if (roomIdSessionMap.containsKey(roomId)) {
            List<Pair<String, Session>> pairs = roomIdSessionMap.get(roomId);
            pairs.add(pair);
            roomIdSessionMap.put(roomId,pairs);
        } else {

            roomIdSessionMap.put(roomId, Lists.newArrayList(pair));
        }
        log.info("room={}当前房间在线人数：{}人",roomId,addOnlineCount(roomId));
        multicastMessage(roomId,userId,"欢迎" +userId+":加入房间");
    }

    /**
     * 服务端接收到信息后调用
     *
     * @param session
     */
    @OnMessage
    public void onMessage(@PathParam("roomId") String roomId, @PathParam("userId") String userId,String msg, Session session) {
        if (StringUtils.isEmpty(roomId) || StringUtils.isEmpty(userId)) {
            log.error("websocket连接 缺少参数");
            throw new IllegalArgumentException("websocket连接 缺少参数");
        }
        multicastMessage(roomId,userId,userId + ":" + msg);
    }

    /**
     * 连接关闭时调用
     */
    @OnClose
    public void onClose(@PathParam("roomId") String roomId,@PathParam("userId") String userId, Session session) {
        if (StringUtils.isEmpty(roomId) || StringUtils.isEmpty(userId)) {
            log.error("websocket连接 缺少参数");
            throw new IllegalArgumentException("websocket连接 缺少参数");
        }
        log.info("一个客户端关闭连接，用户id：{},房间id={}",userId,roomId);
        Pair pair = Pair.of(userId,session);
        if (roomIdSessionMap.containsKey(roomId)) {
            List<Pair<String, Session>> pairs = roomIdSessionMap.get(roomId);
            pairs.remove(pair);
        } else {
            log.error("房间号不存在");
        }
        log.info("room={}当前房间在线人数：{}人",roomId,subOnlineCount(roomId));
        multicastMessage(roomId,userId,userId+":退出房间");
    }

    /**
     * 服务端websocket出错时调用
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("websocket出现错误");
        error.printStackTrace();
    }

    private void multicastMessage(String roomId,String userId,String msg){
        List<Pair<String, Session>> pairs = roomIdSessionMap.get(roomId);
        if (CollectionUtils.isEmpty(pairs)) {
            log.error("room={}房间0人在线",roomId);
        }
        pairs.stream()
                .forEach(e ->{
                    if (userId.equals(e.getFirst())) {
                        return;
                    }
                    try {
                        e.getSecond().getBasicRemote().sendText(msg);
                    } catch (IOException exception) {
                        exception.printStackTrace();
                    }
                });
    }

    public static synchronized int subOnlineCount(String roomId) {
        AtomicInteger atomicInteger = rootNumMap.get(roomId);
        int sub = atomicInteger.decrementAndGet();
        System.out.println("sub = " + sub);
        return sub;
    }

    public static synchronized int getOnlineCount(String roomId) {
        AtomicInteger atomicInteger = rootNumMap.get(roomId);
        int get = atomicInteger.get();
        System.out.println("get = " + get);
        return get;
    }

    public static synchronized int addOnlineCount(String roomId) {
        AtomicInteger atomicInteger = rootNumMap.get(roomId);
        if (ObjectUtils.isEmpty(atomicInteger)) {
            atomicInteger = new AtomicInteger(1);
            rootNumMap.put(roomId, atomicInteger);
            return atomicInteger.get();
        } else {
            return atomicInteger.incrementAndGet();
        }
    }
}
